package controller

import (
	"fmt"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"gorm.io/gorm"

	"github.com/example/video_backend/internal/model"
	"github.com/example/video_backend/internal/service"
	"github.com/example/video_backend/pkg/logger"
	"github.com/example/video_backend/pkg/minio"
	"github.com/example/video_backend/pkg/utils"
	"github.com/gin-gonic/gin"
)

// VideoController 视频控制器
type VideoController struct {
	videoService service.VideoService
}

// NewVideoController 创建视频控制器实例
func NewVideoController(videoService service.VideoService) *VideoController {
	return &VideoController{videoService: videoService}
}

// UploadVideo 上传视频
type UploadVideoRequest struct {
	Title       string `form:"title" binding:"required,min=1,max=100"`
	Description string `form:"description" binding:"max=1000"`
	CategoryID  uint   `form:"category_id" binding:"required,gt=0"`
	Tags        string `form:"tags"` // 标签，用逗号分隔
}

// @Summary 上传视频
// @Description 上传视频文件和相关信息
// @Tags 视频
// @Accept multipart/form-data
// @Produce json
// @Security Bearer
// @Param title formData string true "视频标题"
// @Param description formData string false "视频描述"
// @Param category_id formData int true "分类ID"
// @Param tags formData string false "标签（用逗号分隔）"
// @Param video formData file true "视频文件"
// @Param cover formData file false "封面图片"
// @Success 200 {object} Response{data=model.Video}
// @Router /api/v1/videos [post]
func (c *VideoController) UploadVideo(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userID, exists := ctx.Get("userID")
	if !exists {
		userID = 1
	}

	uid, _ := userID.(uint)

	// 绑定表单数据
	var req UploadVideoRequest
	if err := ctx.ShouldBind(&req); err != nil {
		logger.Error("Upload video request binding error: " + err.Error())
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: err.Error()})
		return
	}

	// 处理视频文件
	videoFile, _ := ctx.FormFile("video")
	if videoFile == nil {
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: "视频文件不能为空"})
		return
	}

	// 处理封面图片
	coverFile, _ := ctx.FormFile("cover")

	// 检查是否为m3u8格式，如果是则转换为mp4
	var videoURL string
	var err error
	var convertedFilePath string
	var convertErr error

	// 获取文件扩展名并转换为小写
	fileExt := strings.ToLower(filepath.Ext(videoFile.Filename))

	if fileExt == ".m3u8" {
		logger.Info("检测到m3u8格式视频，开始转换为mp4格式")
		// 转换m3u8到mp4
		convertedFilePath, _, convertErr = utils.ConvertM3U8ToMP4(videoFile)
		if convertErr != nil {
			logger.Error("Convert m3u8 to mp4 error: " + convertErr.Error())
			ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: "转换视频格式失败: " + convertErr.Error()})
			return
		}
		logger.Info("m3u8转换为mp4成功，准备上传")
		// 上传转换后的视频文件
		videoURL, err = minio.UploadImageFile(ctx, convertedFilePath, "videos/")
		// 清理临时文件
		defer os.Remove(convertedFilePath)
	} else {
		// 上传视频到MinIO - 使用分片上传
		videoURL, err = minio.UploadFile(ctx, videoFile, "videos/")
	}
	if err != nil {
		logger.Error("Upload video file to MinIO error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: "上传视频文件失败"})
		return
	}

	// 上传封面图片到MinIO - 封面图片较小，使用普通上传
	var coverURL string
	if coverFile != nil {
		coverURL, err = minio.UploadFile(ctx, coverFile, "covers/")
		if err != nil {
			logger.Error("Upload cover file to MinIO error: " + err.Error())
			ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: "上传封面图片失败"})
			return
		}
	}

	// 创建视频记录
	err = c.videoService.UploadVideo(ctx, &model.Video{
		UserID:      uid,
		Title:       req.Title,
		Description: req.Description,
		CategoryID:  req.CategoryID,
		VideoURL:    videoURL,
		CoverURL:    coverURL,
	}, videoFile, coverFile)

	if err != nil {
		logger.Error("Create video record error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: err.Error()})
		return
	}

	ctx.JSON(http.StatusOK, Response{Code: 200, Message: "上传成功", Data: map[string]string{
		"video_url": videoURL,
		"cover_url": coverURL,
	}})
}

// GetVideoInfo 获取视频信息
// @Summary 获取视频信息
// @Description 根据视频ID获取视频详细信息
// @Tags 视频
// @Accept json
// @Produce json
// @Param id path int true "视频ID"
// @Success 200 {object} Response{data=model.Video}
// @Router /api/v1/videos/{id} [get]
func (c *VideoController) GetVideoInfo(ctx *gin.Context) {
	// 获取视频ID
	videoID, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: "无效的视频ID"})
		return
	}

	video, err := c.videoService.GetVideoInfo(ctx, uint(videoID))
	if err != nil {
		logger.Error("Get video info error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: err.Error()})
		return
	}

	if video == nil {
		ctx.JSON(http.StatusNotFound, Response{Code: 404, Message: "视频不存在"})
		return
	}

	// 从MinIO获取最新的视频URL（预签名URL）
	// 首先提取视频对象名称
	videoObjectName := extractObjectName(video.VideoURL)
	newVideoURL, err := minio.GetFileURL(ctx, videoObjectName)
	if err != nil {
		logger.Error("Get video URL from MinIO error: " + err.Error())
		// 如果获取新URL失败，使用数据库中存储的旧URL
		newVideoURL = video.VideoURL
	}

	// 如果有封面图片，也获取最新的封面URL
	var newCoverURL string
	if video.CoverURL != "" {
		coverObjectName := extractObjectName(video.CoverURL)
		newCoverURL, err = minio.GetFileURL(ctx, coverObjectName)
		if err != nil {
			logger.Error("Get cover URL from MinIO error: " + err.Error())
			// 如果获取新URL失败，使用数据库中存储的旧URL
			newCoverURL = video.CoverURL
		}
	}

	// 更新视频信息中的URL
	video.VideoURL = newVideoURL
	video.CoverURL = newCoverURL

	// 返回视频信息
	ctx.JSON(http.StatusOK, Response{Code: 200, Message: "获取成功", Data: video})
}

// UpdateVideo 更新视频信息
type UpdateVideoRequest struct {
	Title       string `json:"title" binding:"min=1,max=100"`
	Description string `json:"description" binding:"max=1000"`
	CategoryID  uint   `json:"category_id" binding:"gt=0"`
	Tags        string `json:"tags"` // 标签，用逗号分隔
}

// @Summary 更新视频信息
// @Description 更新视频的基本信息
// @Tags 视频
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "视频ID"
// @Param request body UpdateVideoRequest true "更新视频信息请求参数"
// @Success 200 {object} Response{data=model.Video}
// @Router /api/v1/videos/{id} [put]
func (c *VideoController) UpdateVideo(ctx *gin.Context) {
	// 从上下文中获取用户ID
	//userID, exists := ctx.Get("userID")
	//if !exists {
	//	ctx.JSON(http.StatusUnauthorized, Response{Code: 401, Message: "未登录"})
	//	return
	//}
	//
	//_, ok := userID.(uint)
	//if !ok {
	//	ctx.JSON(http.StatusUnauthorized, Response{Code: 401, Message: "无效的用户ID"})
	//	return
	//}

	// 获取视频ID
	videoID, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: "无效的视频ID"})
		return
	}

	var req UpdateVideoRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		logger.Error("Update video request binding error: " + err.Error())
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: err.Error()})
		return
	}

	video := &model.Video{
		Model: gorm.Model{
			ID: uint(videoID),
		},
		Title:       req.Title,
		Description: req.Description,
		CategoryID:  req.CategoryID,
	}

	err = c.videoService.UpdateVideo(ctx, video)
	if err != nil {
		logger.Error("Update video error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: err.Error()})
		return
	}

	ctx.JSON(http.StatusOK, Response{Code: 200, Message: "更新成功"})
}

// DeleteVideo 删除视频
// @Summary 删除视频
// @Description 根据视频ID删除视频
// @Tags 视频
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "视频ID"
// @Success 200 {object} Response
// @Router /api/v1/videos/{id} [delete]
func (c *VideoController) DeleteVideo(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userID, exists := ctx.Get("userID")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, Response{Code: 401, Message: "未登录"})
		return
	}

	_, ok := userID.(uint)
	if !ok {
		ctx.JSON(http.StatusUnauthorized, Response{Code: 401, Message: "无效的用户ID"})
		return
	}

	// 获取视频ID
	videoID, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: "无效的视频ID"})
		return
	}

	if err := c.videoService.DeleteVideo(ctx, uint(videoID)); err != nil {
		logger.Error("Delete video error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: err.Error()})
		return
	}

	// 从MinIO删除视频文件
	video, err := c.videoService.GetVideoInfo(ctx, uint(videoID))
	if err == nil && video != nil {
		if err := minio.DeleteFile(ctx, video.VideoURL); err != nil {
			logger.Error("Delete video file error: " + err.Error())
		}
		if video.CoverURL != "" {
			if err := minio.DeleteFile(ctx, video.CoverURL); err != nil {
				logger.Error("Delete cover file error: " + err.Error())
			}
		}
	}

	ctx.JSON(http.StatusOK, Response{Code: 200, Message: "删除成功"})
}

// GetVideoList 获取视频列表
type GetVideoListRequest struct {
	Page     int                    `form:"page,default=1" binding:"gt=0"`
	PageSize int                    `form:"page_size,default=10" binding:"gt=0,lt=100"`
	Filter   map[string]interface{} `form:"filter" binding:""`
	UserId   uint
}

// @Summary 获取视频列表
// @Description 获取视频列表，可以按分类、关键词筛选，按最新或最热排序
// @Tags 视频
// @Accept json
// @Produce json
// @Param page query int false "页码，默认1"
// @Param page_size query int false "每页数量，默认10，最大100"
// @Param category_id query int false "分类ID"
// @Param keyword query string false "关键词搜索"
// @Param order_by query string false "排序方式，可选latest或hottest"
// @Success 200 {object} Response{data=map[string]interface{}}
// @Router /api/v1/videos [get]
func (c *VideoController) GetVideoList(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userID, exists := ctx.Get("userID")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, Response{Code: 401, Message: "未登录"})
		return
	}
	var req GetVideoListRequest
	if err := ctx.ShouldBindQuery(&req); err != nil {
		logger.Error("Get video list request binding error: " + err.Error())
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: err.Error()})
		return
	}
	req.UserId = userID.(uint)
	if req.UserId != 0 {
		req.Filter = map[string]interface{}{
			"user_id": req.UserId,
		}
	}
	videos, total, err := c.videoService.ListVideos(ctx, req.Page, req.PageSize, req.Filter)
	if err != nil {
		logger.Error("Get video list error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: err.Error()})
		return
	}

	response := map[string]interface{}{
		"list":      videos,
		"total":     total,
		"page":      req.Page,
		"page_size": req.PageSize,
	}

	ctx.JSON(http.StatusOK, Response{Code: 200, Message: "获取成功", Data: response})
}

// ViewVideo 观看视频
// @Summary 观看视频
// @Description 记录视频观看次数
// @Tags 视频
// @Accept json
// @Produce json
// @Param id path int true "视频ID"
// @Success 200 {object} Response
// @Router /api/v1/videos/{id}/view [post]
func (c *VideoController) ViewVideo(ctx *gin.Context) {
	// 获取视频ID
	videoID, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: "无效的视频ID"})
		return
	}

	//// 从上下文中获取用户ID（如果已登录）
	//userID, exists := ctx.Get("userID")
	//var uid uint
	//if exists {
	//	uid, _ = userID.(uint)
	//}

	if err := c.videoService.WatchVideo(ctx, uint(videoID)); err != nil {
		logger.Error("View video error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: err.Error()})
		return
	}

	ctx.JSON(http.StatusOK, Response{Code: 200, Message: "观看成功"})
}

// LikeVideo 点赞/取消点赞视频
// @Summary 点赞/取消点赞视频
// @Description 对视频进行点赞或取消点赞
// @Tags 视频
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "视频ID"
// @Success 200 {object} Response
// @Router /api/v1/videos/{id}/like [post]
func (c *VideoController) LikeVideo(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userID, exists := ctx.Get("userID")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, Response{Code: 401, Message: "未登录"})
		return
	}

	uid, ok := userID.(uint)
	if !ok {
		ctx.JSON(http.StatusUnauthorized, Response{Code: 401, Message: "无效的用户ID"})
		return
	}

	// 获取视频ID
	videoID, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: "无效的视频ID"})
		return
	}

	err = c.videoService.LikeVideo(ctx, uid, uint(videoID))
	message := "点赞成功"

	if err != nil {
		message = "取消点赞成功"
		logger.Error("Like video error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: err.Error()})
		return
	}

	ctx.JSON(http.StatusOK, Response{Code: 200, Message: message})
}

// CollectVideo 收藏/取消收藏视频
// @Summary 收藏/取消收藏视频
// @Description 对视频进行收藏或取消收藏
// @Tags 视频
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "视频ID"
// @Success 200 {object} Response
// @Router /api/v1/videos/{id}/collect [post]
func (c *VideoController) CollectVideo(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userID, exists := ctx.Get("userID")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, Response{Code: 401, Message: "未登录"})
		return
	}

	uid, ok := userID.(uint)
	if !ok {
		ctx.JSON(http.StatusUnauthorized, Response{Code: 401, Message: "无效的用户ID"})
		return
	}

	// 获取视频ID
	videoID, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: "无效的视频ID"})
		return
	}

	err = c.videoService.CollectVideo(ctx, uid, uint(videoID))
	message := "收藏成功"

	if err != nil {
		message = "取消收藏成功"
		logger.Error("Collect video error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: err.Error()})
		return
	}

	ctx.JSON(http.StatusOK, Response{Code: 200, Message: message})
}

// extractObjectName 从URL中提取MinIO对象名称
func extractObjectName(url1 string) string {
	// 如果URL已经是对象名称（不包含http://或https://），直接返回
	if !strings.HasPrefix(url1, "http://") && !strings.HasPrefix(url1, "https://") {
		// 移除可能的前缀，如"/videos/"或"/covers/"
		return strings.TrimPrefix(strings.TrimPrefix(url1, "/videos/"), "/covers/")
	}

	// 对于完整的URL，我们需要从URL路径中提取对象名称
	parsedURL, err := url.Parse(url1)
	if err != nil {
		return url1
	}

	// 移除路径中的斜杠前缀
	objectName := strings.TrimPrefix(parsedURL.Path, "/")
	return objectName
}

// @Summary 快速上传视频
// @Description 使用分片上传技术快速上传单个视频文件
// @Tags 视频
// @Accept multipart/form-data
// @Produce json
// @Security Bearer
// @Param title formData string true "视频标题"
// @Param description formData string false "视频描述"
// @Param category_id formData int true "分类ID"
// @Param tags formData string false "标签（用逗号分隔）"
// @Param video formData file true "视频文件"
// @Param cover formData file false "封面图片"
// @Success 200 {object} Response{data=model.Video}
// @Router /api/v1/videos/fast [post]
func (c *VideoController) FastUploadVideo(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userID, exists := ctx.Get("userID")
	if !exists {
		userID = 1
	}

	uid, _ := userID.(uint)

	// 绑定表单数据
	var req UploadVideoRequest
	if err := ctx.ShouldBind(&req); err != nil {
		logger.Error("Fast upload video request binding error: " + err.Error())
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: err.Error()})
		return
	}

	// 处理视频文件
	videoFile, _ := ctx.FormFile("video")
	if videoFile == nil {
		ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: "视频文件不能为空"})
		return
	}

	// 处理封面图片
	coverFile, _ := ctx.FormFile("cover")

	// 检查是否为m3u8格式，如果是则转换为mp4
	var videoURL string
	var err error
	var convertedFilePath string
	var convertErr error

	// 获取文件扩展名并转换为小写
	fileExt := strings.ToLower(filepath.Ext(videoFile.Filename))

	if fileExt == ".m3u8" {
		logger.Info("检测到m3u8格式视频，开始转换为mp4格式")
		// 转换m3u8到mp4
		convertedFilePath, _, convertErr = utils.ConvertM3U8ToMP4(videoFile)
		if convertErr != nil {
			logger.Error("Convert m3u8 to mp4 error: " + convertErr.Error())
			ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: "转换视频格式失败: " + convertErr.Error()})
			return
		}
		logger.Info("m3u8转换为mp4成功，准备上传")
		// 上传转换后的视频文件
		videoURL, err = minio.UploadImageFile(ctx, convertedFilePath, "videos/")
		// 清理临时文件
		defer os.Remove(convertedFilePath)
	} else {
		// 上传视频到MinIO - 使用分片上传
		videoURL, err = minio.MultipartUploadFile(ctx, videoFile, "videos/")
	}
	if err != nil {
		logger.Error("Fast upload video file to MinIO error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: "上传视频文件失败"})
		return
	}

	// 上传封面图片到MinIO
	var coverURL string
	if coverFile != nil {
		coverURL, err = minio.UploadFile(ctx, coverFile, "covers/")
		if err != nil {
			logger.Error("Upload cover file to MinIO error: " + err.Error())
			ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: "上传封面图片失败"})
			return
		}
	} else {
		// 如果没有提供封面图，从视频中提取第一帧作为封面图
		logger.Info("No cover image provided, extracting first frame from video")
		framePath, err := utils.ExtractVideoFirstFrame(videoFile)
		if err != nil {
			logger.Error("Extract video first frame error: " + err.Error())
			// 提取失败不影响视频上传，继续处理
		} else {
			// 上传提取的第一帧到MinIO
			coverURL, err = minio.UploadImageFile(ctx, framePath, "covers/")
			if err != nil {
				logger.Error("Upload extracted frame to MinIO error: " + err.Error())
				// 上传失败不影响视频上传，继续处理
			} else {
				logger.Info("Successfully extracted and uploaded first frame as cover")
			}
			// 清理临时文件
			os.Remove(framePath)
		}
	}

	// 创建视频记录
	err = c.videoService.UploadVideo(ctx, &model.Video{
		UserID:      uid,
		Title:       req.Title,
		Description: req.Description,
		CategoryID:  req.CategoryID,
		VideoURL:    videoURL,
		CoverURL:    coverURL,
	}, videoFile, coverFile)

	if err != nil {
		logger.Error("Create video record error: " + err.Error())
		ctx.JSON(http.StatusInternalServerError, Response{Code: 500, Message: err.Error()})
		return
	}

	ctx.JSON(http.StatusOK, Response{Code: 200, Message: "快速上传成功", Data: map[string]string{
		"video_url": videoURL,
		"cover_url": coverURL,
	}})
}

// @Summary 批量上传视频
// @Description 批量上传多个视频文件和相关信息
// @Tags 视频
// @Accept multipart/form-data
// @Produce json
// @Security Bearer
// @Param video0 formData file true "视频文件0"
// @Param title0 formData string true "视频标题0"
// @Param description0 formData string false "视频描述0"
// @Param category_id0 formData int true "分类ID0"
// @Param tags0 formData string false "标签0（用逗号分隔）"
// @Param video1 formData file false "视频文件1"
// @Param title1 formData string false "视频标题1"
// @Param description1 formData string false "视频描述1"
// @Param category_id1 formData int false "分类ID1"
// @Param tags1 formData string false "标签1（用逗号分隔）"
// @Success 200 {object} Response{data=map[string]interface{}}
// @Router /api/v1/videos/batch [post]
func (c *VideoController) BatchUploadVideos(ctx *gin.Context) {
	// 从上下文中获取用户ID
	userID, exists := ctx.Get("userID")
	if !exists {
		userID = 1
	}

	uid, _ := userID.(uint)

	// 存储每个视频的上传结果
	var results []map[string]interface{}
	successCount := 0
	totalCount := 0

	// 遍历所有可能的视频文件（理论上可以上传任意数量）
	for i := 0; ; i++ {
		// 获取视频文件
		videoFile, _ := ctx.FormFile(fmt.Sprintf("video%d", i))
		if videoFile == nil {
			// 没有更多视频文件了
			if i == 0 {
				// 如果没有上传任何视频文件，返回错误
				ctx.JSON(http.StatusBadRequest, Response{Code: 400, Message: "至少需要上传一个视频文件"})
				return
			}
			break
		}

		totalCount++

		// 获取对应的表单数据
		title := ctx.PostForm(fmt.Sprintf("title%d", i))
		description := ctx.PostForm(fmt.Sprintf("description%d", i))
		categoryIDStr := ctx.PostForm(fmt.Sprintf("category_id%d", i))
		_ = ctx.PostForm(fmt.Sprintf("tags%d", i)) // tags字段目前未使用

		// 验证必填字段
		if title == "" {
			results = append(results, map[string]interface{}{
				"index":    i,
				"filename": videoFile.Filename,
				"status":   "failed",
				"message":  "视频标题不能为空",
			})
			continue
		}

		// 解析分类ID
		var categoryID uint = 1
		if categoryIDStr != "" {
			catID, err := strconv.ParseUint(categoryIDStr, 10, 64)
			if err != nil {
				results = append(results, map[string]interface{}{
					"index":    i,
					"filename": videoFile.Filename,
					"status":   "failed",
					"message":  "无效的分类ID",
				})
				continue
			}
			categoryID = uint(catID)
		}

		// 处理封面图片
		coverFile, _ := ctx.FormFile(fmt.Sprintf("cover%d", i))

		// 检查是否为m3u8格式，如果是则转换为mp4
		var videoURL string
		var err error
		var convertedFilePath string

		// 获取文件扩展名并转换为小写
		fileExt := strings.ToLower(filepath.Ext(videoFile.Filename))

		if fileExt == ".m3u8" {
			logger.Info(fmt.Sprintf("检测到m3u8格式视频 %s，开始转换为mp4格式", videoFile.Filename))
			// 转换m3u8到mp4
			var convertErr error
			convertedFilePath, _, convertErr = utils.ConvertM3U8ToMP4(videoFile)
			if convertErr != nil {
				logger.Error(fmt.Sprintf("Convert m3u8 to mp4 error for %s: %s", videoFile.Filename, convertErr.Error()))
				results = append(results, map[string]interface{}{
					"index":    i,
					"filename": videoFile.Filename,
					"status":   "failed",
					"message":  "转换视频格式失败: " + convertErr.Error(),
				})
				continue
			}
			logger.Info(fmt.Sprintf("m3u8转换为mp4成功，准备上传 %s", videoFile.Filename))
			// 上传转换后的视频文件
			videoURL, err = minio.UploadImageFile(ctx, convertedFilePath, "videos/")
			// 清理临时文件
			defer os.Remove(convertedFilePath)
		} else {
			// 上传视频到MinIO
			videoURL, err = minio.UploadFile(ctx, videoFile, "videos/")
		}

		if err != nil {
			logger.Error(fmt.Sprintf("Upload video file %s to MinIO error: %s", videoFile.Filename, err.Error()))
			results = append(results, map[string]interface{}{
				"index":    i,
				"filename": videoFile.Filename,
				"status":   "failed",
				"message":  "上传视频文件失败",
			})
			continue
		}

		// 上传封面图片到MinIO
		var coverURL string
		if coverFile != nil {
			coverURL, err = minio.UploadFile(ctx, coverFile, "covers/")
			if err != nil {
				logger.Error(fmt.Sprintf("Upload cover file for video %s error: %s", videoFile.Filename, err.Error()))
				// 封面上传失败不影响视频上传，继续处理
			}
		} else {
			// 如果没有提供封面图，从视频中提取第一帧作为封面图
			logger.Info(fmt.Sprintf("No cover image provided for video %s, extracting first frame from video", videoFile.Filename))
			framePath, err := utils.ExtractVideoFirstFrame(videoFile)
			if err != nil {
				logger.Error(fmt.Sprintf("Extract video first frame error for %s: %s", videoFile.Filename, err.Error()))
				// 提取失败不影响视频上传，继续处理
			} else {
				// 上传提取的第一帧到MinIO
				coverURL, err = minio.UploadImageFile(ctx, framePath, "covers/")
				if err != nil {
					logger.Error(fmt.Sprintf("Upload extracted frame to MinIO error for %s: %s", videoFile.Filename, err.Error()))
					// 上传失败不影响视频上传，继续处理
				} else {
					logger.Info(fmt.Sprintf("Successfully extracted and uploaded first frame as cover for %s", videoFile.Filename))
				}
				// 清理临时文件
				os.Remove(framePath)
			}
		}

		// 创建视频记录
		err = c.videoService.UploadVideo(ctx, &model.Video{
			UserID:      uid,
			Title:       title,
			Description: description,
			CategoryID:  categoryID,
			VideoURL:    videoURL,
			CoverURL:    coverURL,
		}, videoFile, coverFile)

		if err != nil {
			logger.Error(fmt.Sprintf("Create video record for %s error: %s", videoFile.Filename, err.Error()))
			// 尝试删除已上传的文件
			minio.DeleteFile(ctx, videoURL)
			if coverURL != "" {
				minio.DeleteFile(ctx, coverURL)
			}
			results = append(results, map[string]interface{}{
				"index":    i,
				"filename": videoFile.Filename,
				"status":   "failed",
				"message":  "创建视频记录失败",
			})
			continue
		}

		// 上传成功
		successCount++
		results = append(results, map[string]interface{}{
			"index":     i,
			"filename":  videoFile.Filename,
			"title":     title,
			"video_url": videoURL,
			"cover_url": coverURL,
			"status":    "success",
		})
	}

	// 计算失败数量
	failureCount := totalCount - successCount

	// 返回批量上传结果
	ctx.JSON(http.StatusOK, Response{
		Code:    200,
		Message: fmt.Sprintf("批量上传完成，成功上传 %d 个视频，共 %d 个视频", successCount, totalCount),
		Data: map[string]interface{}{
			"totalCount":   totalCount,
			"successCount": successCount,
			"failureCount": failureCount,
			"results":      results,
		},
	})
}
